#include <jni.h>
#include <string>
#import "native-lib.h"

//通过文件读写，进行socket通信
char const *PATH = "/data/data/caldremch.com.socketprocess/my.sock";
int m_child;
const char *id;

extern "C" JNIEXPORT jstring JNICALL
Java_caldremch_com_socketprocess_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {

}

extern "C"
JNIEXPORT jstring JNICALL
Java_caldremch_com_socketprocess_MyWatcher_stringFromJNI(JNIEnv *env, jobject instance) {

    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

extern "C"
JNIEXPORT void JNICALL
Java_caldremch_com_socketprocess_MyWatcher_socketServer(JNIEnv *env, jobject instance,
                                                        jstring pid_) {
    id = env->GetStringUTFChars(pid_, 0);

    pid_t _pid = fork();

    if (_pid < 0) {
        // fail
    } else if (_pid == 0) {
        //child process
        work();
    } else if (_pid > 0) {
        // parent process
    }
    env->ReleaseStringUTFChars(pid_, id);
}

void work() {
    //分为两部分, 1.创建连接  2.读取消息
    if (create_channel()) {
        listen_message();
    }
}


void listen_message() {

    fd_set fdSet;

    struct timeval timeval1{3, 0};

    while (1) {

        //清空内容
        FD_ZERO(&fdSet);
        FD_SET(m_child, &fdSet);

        int r = select(m_child + 1, &fdSet, NULL, NULL, &timeval1);

        if (r > 0) {

            char buff[256] = {0};

            //阻塞式函数
            LOGE("读取消息后 %d", r);
            read(m_child, buff, sizeof(buff));


            LOGE("在这里 ==  %s", id);

            //
            execlp("am", "am", "startservice", "--user", id,
                   "caldremch.com.socketprocess/caldremch.com.socketprocess.MyPushService", (char *) NULL
            );

            break;

        }

    }

}

int create_channel() {
//socket可以跨进程，文件端口读写  linux文件系统  ip+端口 实际上指明文件
    int listenfd = socket(AF_LOCAL, SOCK_STREAM, 0);
    //之前有连接的, 先解除连接
    unlink(PATH);
    struct sockaddr_un addr;
    ////清空刚刚建立的结构体，全部赋值为零
    memset(&addr, 0, sizeof(sockaddr_un));
    addr.sun_family = AF_LOCAL;
    //addr.sun_data = PATH; 不能够直接赋值,所以使用内存拷贝的方式赋值
    strcpy(addr.sun_path, PATH);

    if (bind(listenfd, (const sockaddr *) &addr, sizeof(sockaddr_un)) < 0) {
        LOGE("绑定错误");
    }

    int connfd = 0;

    listen(listenfd, 5);

    //用死循环保证连接能成功
    while (1) {

        //返回客户端地址 accept是阻塞式函数,返回有两种情况，一种成功，一种失败
        if ((connfd = accept(listenfd, NULL, NULL)) < 0) {

            if (errno == EINTR) {
                //成功的情况下continue继续往后的步骤
                continue;
            } else {
                LOGE("读取错误");
            }

        }

        m_child = connfd;
        LOGE("APK 父进程连接上了 %d", m_child);
        break;

    }

    return 1;

}

extern "C"
JNIEXPORT void JNICALL
Java_caldremch_com_socketprocess_MyWatcher_socketClient(JNIEnv *env, jobject instance) {


    //客户端调用
    int socked;

    struct sockaddr_un addr;

    while (1){


        LOGE("客户端开始连接父进程");


        socked = socket(AF_LOCAL, SOCK_STREAM, 0);

        if (socked < 0){
            LOGE("连接失败");
            return;
        }

        memset(&addr, 0, sizeof(sockaddr_un));
        addr.sun_family = AF_LOCAL;
        strcpy(addr.sun_path, PATH);

        if (connect(socked, (const sockaddr *)(&addr), sizeof(sockaddr_un)) < 0){

            LOGE("连接失败2");

            close(socked);
            sleep(1);
            continue;

        }

        LOGE("连接成功");

        break;

    }

}